package ru.ifmo.thesis.suite;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import ru.ifmo.thesis.domain.Shedule;
import ru.ifmo.thesis.event.Event;
import ru.ifmo.thesis.event.EventListener;
import ru.ifmo.thesis.gp.MyConfigurationOptions;
import ru.ifmo.thesis.suite.CopyOfSuiteRunner.NextGenerationEvolved;
import ru.ifmo.thesis.suite.CopyOfSuiteRunner.StatisticIterationFinished;
import ru.ifmo.thesis.suite.CopyOfSuiteRunner.StatisticIterationStarted;
import ru.ifmo.thesis.suite.CopyOfSuiteRunner.TaskStartedEvent;
import ru.ifmo.thesis.util.Algorithms;
import ru.ifmo.thesis.util.SequenceGeneratortor;

public class ParamDetectXLSXLogger {

	private static final double POW = Math.pow(10, 9);

	public class StatisticIterationFinishedListener implements EventListener {

		@Override
		public void fireEvent(Event event) {
			StatisticIterationFinished e = (StatisticIterationFinished) event;
			
			MyConfigurationOptions options = e.getOptions();
			
			List<Shedule> shedules = e.getShedules();
			long timeInterval = e.getTimeInterval();
			
			logIteration(options, shedules, timeInterval);
		}
	}

	public class TaskStartedEventListener implements EventListener {

		@Override
		public void fireEvent(Event event) {
			TaskStartedEvent e = (TaskStartedEvent) event;
			currentFineValue = e.getFineValue();
			currentTask = e.getNumber();
			currentIteration = 0;
		}
	}

	public class StatisticIterationStartedListener implements EventListener {

		@Override
		public void fireEvent(Event event) {
			currentIteration++;
			currentGenerationEvolvedCount = 0;
			row = sheet.createRow(rowIndex.nextValue());
		}
	}

	public class NextGenerationEvolvedListener implements EventListener {
		@Override
		public void fireEvent(Event event) {
			NextGenerationEvolved e = (NextGenerationEvolved) event;
			currentBestAnswer = e.getSheduleCost();
			currentGenerationEvolvedCount++;
			
//			logIteration(e.getOptions(), e.getAllShedules(), e.getTime());
//			row = sheet.createRow(rowIndex.nextValue());
		}
	}

	private double currentFineValue;
	
	private final String fileName;
	
	private final CopyOfSuiteRunner suiteRunner;
	
	private static final String NEW_SHEET_NAME = "new sheet";

	private Workbook workbook;

	private Sheet sheet;
	
	private Row row;

	private SequenceGeneratortor rowIndex = new SequenceGeneratortor(0);
	
	private SequenceGeneratortor cellIndex = new SequenceGeneratortor(0);
	
	private int currentTask = 0;
	
	private int currentIteration = 0;
	
	private double currentBestAnswer = 0;
	
	private int currentGenerationEvolvedCount = 0;
	
	public ParamDetectXLSXLogger(String outputFileName, CopyOfSuiteRunner suiteRunner) {
		this.fileName = outputFileName;
		this.suiteRunner = suiteRunner;
		
		this.workbook = new XSSFWorkbook();
		
		this.sheet = workbook.createSheet(NEW_SHEET_NAME);
		
		writeHeader();
		
		suiteRunner.addEventListener(StatisticIterationStarted.NAME, new StatisticIterationStartedListener());
		suiteRunner.addEventListener(NextGenerationEvolved.NAME, new NextGenerationEvolvedListener());
		suiteRunner.addEventListener(TaskStartedEvent.NAME, new TaskStartedEventListener());
		suiteRunner.addEventListener(StatisticIterationFinished.NAME, new StatisticIterationFinishedListener());
	}
	
	private void writeHeader() {
		row = sheet.createRow(rowIndex.nextValue());
		cellIndex = new SequenceGeneratortor(0);

		createCell().setCellValue("TASK_NO");
		createCell().setCellValue("ITERATION");
		createCell().setCellValue("FINE_VAL");
		createCell().setCellValue("BEST_FOUND");
		createCell().setCellValue("GENERATIONS_EVOLVED");
		createCell().setCellValue("TIME_SEC");

		createCell().setCellValue("Second");
		createCell().setCellValue("Third");
		createCell().setCellValue("Fourth");
		
		createCell().setCellValue("Average");

		createCell().setCellValue("mutationPercent");
		createCell().setCellValue("AllowDoubletteChromosomes");
		createCell().setCellValue("MovingsPerMutation");
		createCell().setCellValue("ofPopulation");
		createCell().setCellValue("SwappingRate");
		createCell().setCellValue("SelectFromPrevGen");
		createCell().setCellValue("TakePercentToNewPopulation");
		createCell().setCellValue("CrossoverRate");
	}

	private void writeOutData() {
		FileOutputStream results;
		try {
			fileName.replace(".xlsx", " " + System.currentTimeMillis() + ".xlsx");
			results = new FileOutputStream(fileName);
			workbook.write(results);
			results.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	private Cell createCell() {
		return row.createCell(cellIndex.nextValue());
	}
	
	public void close() {
		writeOutData();
	}
	
	private void logIteration(MyConfigurationOptions options,
			List<Shedule> shedules, long timeInterval) {
		
		cellIndex = new SequenceGeneratortor(0);
		createCell().setCellValue(currentTask);
		createCell().setCellValue(currentIteration);
		createCell().setCellValue(currentFineValue);
		createCell().setCellValue(currentBestAnswer);
		createCell().setCellValue(currentGenerationEvolvedCount);
		createCell().setCellValue(timeInterval / POW);
		
		createCell().setCellValue(Algorithms.calculateSheduleCost(shedules.get(1)));
		createCell().setCellValue(Algorithms.calculateSheduleCost(shedules.get(2)));
		createCell().setCellValue(Algorithms.calculateSheduleCost(shedules.get(3)));
		
		createCell().setCellValue(avg(shedules));
		
		createCell().setCellValue(options.getMutationPercent());
		createCell().setCellValue(options.isAllowDoubletteChromosomes());
		createCell().setCellValue(options.getMovingsPerMutation());
		createCell().setCellValue(options.getOfPopulation());
		createCell().setCellValue(options.getSwappingRate());
		createCell().setCellValue(options.getSelectFromPrevGen().value());
		createCell().setCellValue(options.getTakePercentToNewPopulation().value());
		createCell().setCellValue(options.getCrossoverRate().value());
	}

	private double avg(List<Shedule> shedules) {
		double summ = 0;
		for (Shedule s : shedules) {
			summ += Algorithms.calculateSheduleCost(s);
		}
		return summ / shedules.size();
	}
}
